<template>
    <div class="att-wrap" v-if="attachments && attachments.length">
      <!-- 顶部工具条 -->
      <div class="att-toolbar">
        <div class="left">
          <el-tag type="success" v-if="images.length">图片 {{ images.length }}</el-tag>
          <el-tag type="info" v-if="others.length" class="ml8">文件 {{ others.length }}</el-tag>
        </div>
        <div class="right">
          <el-button type="primary" @click="downloadAllZip" :loading="downloading">
            批量下载（{{ attachments.length }}）
          </el-button>
        </div>
      </div>
  
      <!-- 图片宫格 -->
      <div v-if="images.length" class="img-grid">
        <el-image
          v-for="(img, idx) in images"
          :key="img.id || idx"
          class="img-thumb"
          :src="resolveUrl(img.fileUrl)"
          :alt="img.fileName"
          fit="cover"
          :preview-src-list="imgPreviewList"
          :initial-index="idx"
          hide-on-click-modal
          preview-teleported
        />
      </div>
  
      <!-- 其他文件列表（含 PDF 预览） -->
      <div v-if="others.length" class="file-list">
        <el-card
          v-for="f in others"
          :key="f.id || f.fileUrl"
          shadow="hover"
          class="file-item"
          @dblclick="onDblClick(f)"
        >
          <div class="file-row">
            <el-icon class="file-ico"><Document /></el-icon>
  
            <div class="file-main">
              <div class="file-name" :title="f.fileName">{{ f.fileName }}</div>
              <div class="file-meta">
                <span>{{ formatSize(f.fileSize) }}</span>
                <span class="dot">·</span>
                <span>{{ f.fileType || "-" }}</span>
                <span class="dot">·</span>
                <span>{{ f.uploadTime || "" }}</span>
              </div>
            </div>
  
            <div class="file-ops">
              <!-- <el-button v-if="isPdf(f)" link type="primary" @click.stop="previewPdf(f)">预览</el-button> -->
              <el-button v-if="isPdf(f)" link type="primary" @click.stop="openInNewTab(f)">预览</el-button>
              <el-button link @click.stop="downloadOne(f)">下载</el-button>
            </div>
          </div>
        </el-card>
      </div>
  
      <!-- PDF 预览弹窗 --> 
<el-dialog
  v-model="pdfVisible"
  class="pdf-dialog"           
  modal-class="pdf-overlay"     
  append-to-body                
  :z-index="4000"              
  :lock-scroll="true"           
  :destroy-on-close="true"
  :close-on-click-modal="false"
  width="90vw"
  top="4vh"
>
  <div class="pdf-box">
    <iframe
      v-if="pdfSrc"
      :src="pdfSrc"
      class="pdf-iframe"
      frameborder="0"
    />
    <el-empty v-else description="加载中..." />
  </div>
</el-dialog>

    </div>
  </template>
  
  <script>
  import { computed, ref } from "vue";
  import { ElMessage } from "element-plus";
  import { Document } from "@element-plus/icons-vue";
  import axios from "axios";
  
  /** 若依常见封装：如你已有这两个工具，请保留 import；没有也可用下面的简易后备实现 */
  // import { downloadOrderAttachmentsZip } from "@/api/sbtz/attachment";
  // import { parseFilenameFromCD, saveBlob } from "@/utils/generator/download";
  
  /* ---- 后备实现（项目里已有可删除） ---- */
  async function downloadOrderAttachmentsZip(params) {
    // 预留：你的真实接口路径
    const BASE = import.meta.env.VITE_APP_BASE_API || "";
    const url = `${BASE}/sbtz/attachment/downloadZip`;
    return axios.post(url, params, { responseType: "blob" });
  }
  function parseFilenameFromCD(cd, fallbackName) {
    if (!cd) return fallbackName;
    try {
      const m = cd.match(/filename\*=UTF-8''([^;]+)|filename="?([^"]+)"?/i);
      return decodeURIComponent(m[1] || m[2] || fallbackName);
    } catch {
      return fallbackName;
    }
  }
  function saveBlob(blob, filename) {
    const url = URL.createObjectURL(blob);
    const a = document.createElement("a");
    a.href = url;
    a.download = filename || "download";
    document.body.appendChild(a);
    a.click();
    URL.revokeObjectURL(url);
    a.remove();
  }
  /* ----------------------------------- */
  
  export default {
    name: "AttachmentCellForRuoYi",
    components: { Document },
    props: {
      /** 附件数组：[{ fileUrl, fileName, fileType, fileSize, uploadTime, id }] */
      attachments: { type: Array, default: () => [] },
      /** 工单 ID，用于后端打包 zip */
      orderId: { type: [Number, String], default: null },
    },
    setup(props) {
      const BASE = import.meta.env.VITE_APP_BASE_API || ""; // /dev-api 或 /prod-api
      const downloading = ref(false);
  
      const isImage = (a) => {
        const t = (a?.fileType || "").toLowerCase();
        if (t.startsWith("image/")) return true;
        const n = (a?.fileName || "").toLowerCase();
        return /\.(png|jpe?g|gif|bmp|webp|svg)$/.test(n);
      };
      const isPdf = (a) => {
        const t = (a?.fileType || "").toLowerCase();
        if (t.includes("application/pdf")) return true;
        const n = (a?.fileName || "").toLowerCase();
        return /\.pdf$/.test(n);
      };
  
      const images = computed(() => (props.attachments || []).filter(isImage));
      const others = computed(() => (props.attachments || []).filter((a) => !isImage(a)));
  
      const resolveUrl = (u) => {
        if (!u) return "";
        if (/^https?:\/\//i.test(u)) return u;
        // 若依：相对路径统一加 BASE；保证只有一个 '/'
        return `${BASE.replace(/\/+$/, "")}/${String(u).replace(/^\/+/, "")}`;
      };
  
      const imgPreviewList = computed(() => images.value.map((img) => resolveUrl(img.fileUrl)));
  
      const formatSize = (n) => {
        if (!n || n <= 0) return "-";
        const units = ["B", "KB", "MB", "GB"];
        let i = 0,
          v = n;
        while (v >= 1024 && i < units.length - 1) {
          v /= 1024;
          i++;
        }
        return `${v.toFixed(i === 0 ? 0 : 1)} ${units[i]}`;
      };
  
      const openInNewTab = (f) => window.open(resolveUrl(f.fileUrl), "_blank");
  
      const downloadBlob = (blob, fileName) => {
        const url = URL.createObjectURL(blob);
        const a = document.createElement("a");
        a.href = url;
        a.download = fileName || "download";
        a.style.display = "none";
        document.body.appendChild(a);
        a.click();
        URL.revokeObjectURL(url);
        a.remove();
      };
  
      const downloadOne = async (f) => {
        try {
          const res = await axios.get(resolveUrl(f.fileUrl), { responseType: "blob" });
          downloadBlob(res.data, f.fileName || "附件");
        } catch (e) {
          ElMessage.error("下载失败");
        }
      };
  
      const onDblClick = (f) => {
        if (isPdf(f)) previewPdf(f);
        else openInNewTab(f);
      };
  
      /** PDF 预览（优先 blob，鉴权或跨域失败就新开标签页） */
      const pdfVisible = ref(false);
      const pdfSrc = ref("");
  
      const previewPdf = async (f) => {
        const url = resolveUrl(f.fileUrl);
        pdfSrc.value = "";
        pdfVisible.value = true;
        try {
          const res = await axios.get(url, { responseType: "blob" });
          const type = (res.headers["content-type"] || "").toLowerCase();
          if (!type.includes("application/pdf")) {
            window.open(url, "_blank");
            pdfVisible.value = false;
            return;
          }
          pdfSrc.value = URL.createObjectURL(res.data);
        } catch (e) {
          window.open(url, "_blank");
          pdfVisible.value = false;
        }
      };
  
      // 批量下载（后端打包 ZIP）
      const downloadAllZip = async () => {
        if (!props.orderId) return;
        try {
          downloading.value = true;
          const res = await downloadOrderAttachmentsZip({ orderId: props.orderId });
          const blob = res?.data instanceof Blob ? res.data : res;
          const cd = res?.headers?.["content-disposition"] || res?.headers?.["Content-Disposition"];
          const filename = parseFilenameFromCD(cd, `工单${props.orderId}-附件.zip`);
          saveBlob(blob, filename);
        } finally {
          downloading.value = false;
        }
      };
  
      return {
        // state
        downloading,
        images,
        others,
        imgPreviewList,
        pdfVisible,
        pdfSrc,
        // methods
        isPdf,
        resolveUrl,
        formatSize,
        openInNewTab,
        downloadOne,
        onDblClick,
        previewPdf,
        downloadAllZip,
      };
    },
  };
  </script>
  
  <style scoped>
  .att-toolbar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: 12px;
  }
  .ml8 {
    margin-left: 8px;
  }
  .img-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
    gap: 10px;
    margin-bottom: 12px;
  }
  .img-thumb {
    width: 100%;
    height: 110px;
    border-radius: 10px;
    overflow: hidden;
    box-shadow: 0 1px 4px rgba(0, 0, 0, 0.07);
  }
  .file-list {
    display: grid;
    gap: 10px;
  }
  .file-item {
    border-radius: 10px;
  }
  .file-row {
    display: flex;
    align-items: center;
    gap: 12px;
  }
  .file-ico {
    font-size: 22px;
  }
  .file-main {
    flex: 1;
    min-width: 0;
  }
  .file-name {
    font-weight: 600;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }
  .file-meta {
    font-size: 12px;
    color: #999;
    margin-top: 4px;
    display: flex;
    align-items: center;
    gap: 6px;
  }
  .dot {
    opacity: 0.5;
  }
  .file-ops {
    white-space: nowrap;
  }
  .pdf-box {
    height: 75vh;
  }
  .pdf-iframe {
    width: 100%;
    height: 100%;
  }

  /* 覆盖遮罩层级 */
:deep(.pdf-overlay) {
  z-index: 3999 !important; /* 小于对话框本体的 4000 即可 */
}

/* 去掉 dialog body 默认 padding，避免出现背景边缝 */
.pdf-dialog :deep(.el-dialog__body) {
  padding: 0;
}

/* 让 iframe 完整覆盖，背景纯白避免透出 */
.pdf-box {
  height: calc(100vh - 12vh); /* 90vw 宽、4vh 顶距，根据你的宽高自行调整 */
  background: #fff;
}
.pdf-iframe {
  display: block;
  width: 100%;
  height: 100%;
  background: #fff; /* 防止透明导致看见底层 */
  border: 0;
}

  </style>
  